﻿using System;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace AreaBuilder.Controls {
    public class MobProgTextBox : RichTextBox {
        public MobProgTextBox() {
            TextChanged += highlightSyntax;
        }

        public void Indent() {
            String[] lines = IndentMobprog(Text.Split(Environment.NewLine.ToCharArray()));
            Clear();

            foreach (String line in lines) {
                if (String.IsNullOrEmpty(line.Trim()))
                    continue;

                Text += line;
                Text += Environment.NewLine;
            }

            Text = Regex.Replace(Text, @"\n{2,}", "");
        }

        private static String[] IndentMobprog(String[] lines) {
            var ifCheck = new Regex(@"^\s*if\s+");
            var endifCheck = new Regex(@"^\s*endif\s*");
            var elseCheck = new Regex(@"^\s*else\s*");
            var output = new String[lines.Length];
            int indent = 0;

            for (int i = 0; i < lines.Length; i++) {
                Match ifMatch = ifCheck.Match(lines[i].Trim());
                Match endifMatch = endifCheck.Match(lines[i].Trim());
                Match elseMatch = elseCheck.Match(lines[i].Trim());

                if (endifMatch.Success || elseMatch.Success)
                    indent -= 2;

                if (elseMatch.Success && indent < 0)
                    MessageBox.Show("You have a possible mobprog error! (i.e., extra else)", "Oops!",
                                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                output[i] = String.Format("{0}{1}", Spaces(indent), lines[i].Trim());

                if (ifMatch.Success || elseMatch.Success)
                    indent += 2;
            }

            if (indent != 0)
                MessageBox.Show("You have a possible mobprog error! (i.e., missing [or extra] else/endif)", "Oops!",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

            return output;
        }

        private static String Spaces(int number) {
            var sb = new StringBuilder();
            for (int i = 0; i < number; i++)
                sb.Append(" ");

            return sb.ToString();
        }

        private void highlightSyntax(object sender, EventArgs e) {
            int origCaret = SelectionStart;

            String commands = Funcs.getXPath("/types/commands/cmd");
            var keywordRegex =
                new Regex(
                    @"(?:^\s*\bif|^\s*\bendif|^\s*\belse|(?<=^\s*if\b\s*)(?:isrroom|israrea|isnpc|ispc|isgood|isneutral|isevil|isimmort|ischarm|isfollow|isactive|isdelay|isvisible|hastarget|istarget|rand|mobhere|objhere|mobexists|objexists|people|players|mobs|clones|order|hour|vnum|hpcnt|room|sex|level|align|money|objval[0-4]))\b",
                    RegexOptions.Multiline);
            var identifierRegex =
                new Regex(
                    @"(?:\$i|\$I|\$n|\$N|\$t|\$T|\$r|\$R|\$q|\$Q|\$j|\$e|\$E|\$J|\$k|\$m|\$M|\$K|\$l|\$s|\$S|\$L|\$o|\$O|\$p|\$P)",
                    RegexOptions.Multiline);
            var operatorsRegex = new Regex(@"==|!=|>|<|>=|<=", RegexOptions.Multiline);
            var vnumRegex = new Regex(@"\d{4,}", RegexOptions.Multiline);
            var commandsRegex =
                new Regex(
                    String.Format(
                        @"(\bmob\b\s*\b(asound|zecho|gecho|echo|echoat|echoaround|mload|oload|kill|flee|follow|remove|junk|purge|at|goto|trans(fer)?|gtransfer|otransfer|force|gforce|vforce|cast|damage|delay|cancel|remember|forget|call)\b)|^\s*\b({0})\b",
                        commands), RegexOptions.Multiline);

            // Everything is an argument until proven otherwise?

            Select(0, Text.Length);
            SelectionColor = Color.DarkGray;
            SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Regular);

            foreach (Match m in vnumRegex.Matches(Text)) {
                Select(m.Index, m.Length);
                SelectionColor = Color.Gold;
                SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            }


            foreach (Match m in keywordRegex.Matches(Text)) {
                Select(m.Index, m.Length);
                SelectionColor = Color.Blue;
                SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            }

            foreach (Match m in identifierRegex.Matches(Text)) {
                Select(m.Index, m.Length);
                SelectionColor = Color.Green;
                SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            }

            foreach (Match m in operatorsRegex.Matches(Text)) {
                Select(m.Index, m.Length);
                SelectionColor = Color.Red;
                SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            }

            foreach (Match m in commandsRegex.Matches(Text)) {
                Select(m.Index, m.Length);
                SelectionColor = Color.Brown;
                SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Bold);
            }

            SelectionStart = origCaret;
            SelectionLength = 0;
            SelectionColor = Color.Black;
            SelectionFont = new Font("Microsoft Sans Serif", 8, FontStyle.Regular);
        }
    }
}